package com.hoshiicloud.mallshop.service.impl;

import com.google.common.collect.Maps;
import com.hoshiicloud.common.query.OmnipotentWrapper;
import com.hoshiicloud.mallshop.feign.ShopSaleOrderFeignService;
import com.hoshiicloud.mallshop.feign.ShopUserFeignService;
import com.hoshiicloud.mallshop.service.StoreHomePageService;
import com.hoshiicloud.saleorder.entity.OrderMain;
import com.hoshiicloud.saleorder.entity.RefundOrder;
import com.hoshiicloud.user.entity.visitors.Visitors;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.crypto.hash.Hash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 店铺首页
 *
 * @author linjx on 2019/8/30
 */
@Slf4j
@Service
public class StoreHomePageServiceImpl implements StoreHomePageService {

    @Autowired
    private ShopSaleOrderFeignService shopSaleOrderFeignService;
    @Autowired
    private ShopUserFeignService userFeignService;

    /**
     * 获取店铺首页顶部信息
     */
    @Override
    public Map<String, Object> getHomePageTop(Long storeId) {

        // 设置需要返回的值
        Map<String, Object> map = new HashMap<>();

        // 等待买家付款
        Integer waitBuyerPay = this.waitBuyerPay(storeId);
        // 等待商家配送
        Integer waitBusinessDelivery = this.waitBusinessDelivery(storeId);
        // 退款中
        Integer inRefunds = this.inRefund(storeId);

        // 等待买家提货
        Integer waitBuyerTakeGoods = this.waitBuyerTakeGoods(storeId);

        map.put("waitBuyerPay", waitBuyerPay);
        map.put("waitBusinessDelivery", waitBusinessDelivery);
        map.put("inRefunds", inRefunds);

        map.put("waitBuyerTakeGoods", waitBuyerTakeGoods);
        return map;
    }

    /**
     * 交易总览
     */
    @Override
    public Map<String, Object> transactionsView(Integer aheadDays, Long storeId) {

        HashMap<String, Object> backMap = new HashMap<>();
        // 获取相对日期的主订单： 例如：如果aheadDays=1 就获取昨天和前天的主订单信息
        Map<String, List<OrderMain>> map = this.listRelativeOrderMains(aheadDays, storeId);
        List<OrderMain> aheadDayOrderMains = map.get("aheadDayOrderMains");
        List<OrderMain> aheadDoubleDayOrderMains = map.get("aheadDoubleDayOrderMains");

        // 获得相对日期的访客数
        Map<String, List<Visitors>> visitorsMap = this.listRelativeVisitors(aheadDays, storeId);
        List<Visitors> numDaysAgoVisitors = visitorsMap.get("numDaysAgoVisitors");
        List<Visitors> doubleNumDaysAgoVisitors = visitorsMap.get("doubleNumDaysAgoVisitors");

        // 交易总览：访客数
        backMap.put("visitorsNumView", this.visitorsNumView(numDaysAgoVisitors, doubleNumDaysAgoVisitors));
        // 交易总览: 下单买家数
        backMap.put("orderBuyerView", this.orderBuyerView(aheadDayOrderMains, aheadDoubleDayOrderMains));
        // 交易总览： 下单金额
        backMap.put("orderAmountView", this.orderAmountView(aheadDayOrderMains, aheadDoubleDayOrderMains));
        // 交易总览: 支付买家数
        backMap.put("payBuyerView", this.payBuyerView(aheadDayOrderMains, aheadDoubleDayOrderMains));
        // 交易总览： 支付金额
        backMap.put("payAmountView", this.payAmountView(aheadDayOrderMains, aheadDoubleDayOrderMains));
        // 交易总览： 客单价
        backMap.put("unitPriceView", this.unitPriceView(aheadDayOrderMains, aheadDoubleDayOrderMains));
        // 交易总览： 转化率
        backMap.put("conversionRate", this.conversionRate(aheadDayOrderMains, numDaysAgoVisitors));

        return backMap;
    }

    /**
     * 趋势图
     */
    @Override
    public Map<String, Object> trendChart(Integer aheadDays, Long storeId) {

        Map<String, Object> trendChartMap = new HashMap<>();

        LocalDateTime now = LocalDateTime.now();
        // 查询主订单并且按天分组
        Map<LocalDateTime, List<OrderMain>> orderMainsGroupByDay = this.listGroupOrderMains(aheadDays, storeId, now);
        // 查询访客数并且按天分组
        Map<LocalDateTime, List<Visitors>> visitorGroupByDay = this.listGroupVisitors(aheadDays, storeId, now);

        // 下单支付转化率趋势图
        trendChartMap.put("orderPayRate", this.orderPayRateTrendChart(orderMainsGroupByDay));
        // 支付转化率趋势图
        trendChartMap.put("payVisitorsRate", this.payVisitorsTrendChart(orderMainsGroupByDay, visitorGroupByDay));
        // 支付买家趋势图
        trendChartMap.put("payBuyer",this.payBuyerTrendChart(orderMainsGroupByDay));
        // 下单买家趋势图
        trendChartMap.put("orderBuyer", this.orderBuyerTrendChart(orderMainsGroupByDay));
        // 客单价趋势图
        trendChartMap.put("unitPrice", this.unitPriceTrendChart(orderMainsGroupByDay));
        return trendChartMap;
    }

    // ==============================顶部===========================================
    /** 等待买家付款 */
    private Integer waitBuyerPay(Long storeId) {
        List<OmnipotentWrapper> waitBuyerPay = new ArrayList<>();
        waitBuyerPay.add(OmnipotentWrapper.setWrapper("eq", "order_status", 0));
        waitBuyerPay.add(OmnipotentWrapper.setWrapper("eq", "store_id", storeId));
        waitBuyerPay.add(OmnipotentWrapper.setWrapper("eq", "deleted", 0));
        List<OrderMain> waitBuyerPays = shopSaleOrderFeignService.omniQueryOrderMain(waitBuyerPay).getData();
        return waitBuyerPays.isEmpty() ? 0: waitBuyerPays.size();
    }

    /**  等待商家配送 */
    private Integer waitBusinessDelivery(Long storeId) {
        List<OmnipotentWrapper> waitBusinessDelivery = new ArrayList<>();
        waitBusinessDelivery.add(OmnipotentWrapper.setWrapper("eq", "order_status", 6));
        waitBusinessDelivery.add(OmnipotentWrapper.setWrapper("eq", "store_id", storeId));
        waitBusinessDelivery.add(OmnipotentWrapper.setWrapper("eq", "deleted", 0));
        List<OrderMain> waitDeliver = shopSaleOrderFeignService.omniQueryOrderMain(waitBusinessDelivery).getData();
        return waitDeliver.isEmpty() ? 0: waitDeliver.size();
    }

    /** 退款中 */
    private Integer inRefund(Long storeId) {
        // 在refund_order 中查询退款中的订单， 获取主单id, 去重即为正在退款中的订单数
        List<OmnipotentWrapper> refundOrderWrappers = new ArrayList<>();
        refundOrderWrappers.add(OmnipotentWrapper.setWrapper("eq", "store_id", storeId));
        refundOrderWrappers.add(OmnipotentWrapper.setWrapper("lt", "status", 5));
        List<RefundOrder> refundOrders = shopSaleOrderFeignService.omniRefundOrder(refundOrderWrappers).getData();
        if (refundOrders.isEmpty()) {return 0;}
        List<Long> mainIds = refundOrders.stream().map(RefundOrder::getMainId).distinct().collect(Collectors.toList());
        return mainIds.isEmpty() ? 0 : mainIds.size();
    }

    /** TODO 换货中 */
    private Integer exchangeOrder(Long storeId) {
        // 1 查询正在换货的订单（status = 0） 2 通过sub_id 查询子单信息-> 获取主单id去重， 即为换货中的订单数


        return null;
    }

    /** 等待买家提货 */
    private Integer waitBuyerTakeGoods(Long storeId) {
        List<OmnipotentWrapper> takeGoodsSet = new ArrayList<>();
        takeGoodsSet.add(OmnipotentWrapper.setWrapper("eq", "order_status", 5));
        takeGoodsSet.add(OmnipotentWrapper.setWrapper("eq", "store_id", storeId));
        takeGoodsSet.add(OmnipotentWrapper.setWrapper("eq", "deleted", 0));
        List<OrderMain> takeGoods = shopSaleOrderFeignService.omniQueryOrderMain(takeGoodsSet).getData();
        return takeGoods.isEmpty()? 0: takeGoods.size();
    }

    // ==============================交易总览===========================================

    /** 交易总览：访客数  */
    private Map<String, Object> visitorsNumView(List<Visitors> numDaysAgoisitors, List<Visitors> doubleNumDaysAgoisitors) {

        float aheadDayNum;
        float aheadDoubleDayNum;

        aheadDayNum = numDaysAgoisitors.isEmpty()? 0:numDaysAgoisitors.size();
        aheadDoubleDayNum = doubleNumDaysAgoisitors.isEmpty()? 0: doubleNumDaysAgoisitors.size();

        return this.getTransactionDate("number", aheadDayNum, aheadDoubleDayNum);

    }

    /** 交易总览： 下单买家数 */
    private Map<String, Object> orderBuyerView(List<OrderMain> aheadDayOrderMains, List<OrderMain> aheadDoubleDayOrderMains) {

        float aheadDayNum;
        float aheadDoubleDayNum;

        aheadDayNum = aheadDayOrderMains.isEmpty()? 0f: Float.parseFloat(aheadDayOrderMains.stream().map(OrderMain::getMemberId).distinct().count()+"");
        aheadDoubleDayNum = aheadDoubleDayOrderMains.isEmpty()? 0f: Float.parseFloat(aheadDoubleDayOrderMains.stream().map(OrderMain::getMemberId).distinct().count()+"");

        return this.getTransactionDate("number", aheadDayNum, aheadDoubleDayNum);
    }

    /** 交易总览： 下单金额 */
    private Map<String, Object> orderAmountView(List<OrderMain> aheadDayOrderMains, List<OrderMain> aheadDoubleDayOrderMains) {

        float aheadDayNum;
        float aheadDoubleDayNum;

        aheadDayNum = aheadDayOrderMains.isEmpty()? 0f: aheadDayOrderMains.stream().map(OrderMain::getOrderAmount).reduce(BigDecimal.ZERO, BigDecimal::add).floatValue();
        aheadDoubleDayNum = aheadDoubleDayOrderMains.isEmpty()? 0f: aheadDoubleDayOrderMains.stream().map(OrderMain::getOrderAmount).reduce(BigDecimal.ZERO, BigDecimal::add).floatValue();

        return this.getTransactionDate("number", aheadDayNum, aheadDoubleDayNum);
    }

    /** 交易总览： 支付买家数 */
    private Map<String, Object> payBuyerView(List<OrderMain> aheadDayOrderMains, List<OrderMain> aheadDoubleDayOrderMains) {

        float aheadDayNum;
        float aheadDoubleDayNum;

        aheadDayNum = aheadDayOrderMains.isEmpty()? 0f: Float.parseFloat(aheadDayOrderMains.stream().filter(s -> s.getPaidTime() != null).map(OrderMain::getMemberId).distinct().count()+"");
        aheadDoubleDayNum = aheadDoubleDayOrderMains.isEmpty()? 0f: Float.parseFloat(aheadDoubleDayOrderMains.stream().filter(s -> s.getPaidTime() != null).map(OrderMain::getMemberId).distinct().count()+"");

        return this.getTransactionDate("number", aheadDayNum, aheadDoubleDayNum);
    }

    /** 交易总览： 支付金额 */
    private Map<String, Object> payAmountView(List<OrderMain> aheadDayOrderMains, List<OrderMain> aheadDoubleDayOrderMains) {

        float aheadDayNum;
        float aheadDoubleDayNum;

        aheadDayNum = aheadDayOrderMains.isEmpty()? 0f: aheadDayOrderMains.stream().filter(s -> s.getPaidTime() != null).map(OrderMain::getOrderAmount).reduce(BigDecimal.ZERO, BigDecimal::add).floatValue();
        aheadDoubleDayNum = aheadDoubleDayOrderMains.isEmpty()? 0f: aheadDoubleDayOrderMains.stream().filter(s -> s.getPaidTime() != null).map(OrderMain::getOrderAmount).reduce(BigDecimal.ZERO, BigDecimal::add).floatValue();

        return this.getTransactionDate("number", aheadDayNum, aheadDoubleDayNum);
    }

    /** 交易总览： 客单价 */
    private Map<String, Object> unitPriceView(List<OrderMain> aheadDayOrderMains, List<OrderMain> aheadDoubleDayOrderMains) {

        float aheadDayNum;
        float aheadDoubleDayNum;

        // 客单价 = 指定时间段内订单应付总金额/ 订单数量
        aheadDayNum = aheadDayOrderMains.isEmpty()? 0f: aheadDayOrderMains.stream().map(OrderMain::getOrderAmount).reduce(BigDecimal.ZERO, BigDecimal::add).floatValue()/ Float.parseFloat(aheadDayOrderMains.size()+"");
        aheadDoubleDayNum = aheadDoubleDayOrderMains.isEmpty()? 0f: aheadDoubleDayOrderMains.stream().map(OrderMain::getOrderAmount).reduce(BigDecimal.ZERO, BigDecimal::add).floatValue()/Float.parseFloat(aheadDoubleDayOrderMains.size()+"");

        return this.getTransactionDate("number", aheadDayNum, aheadDoubleDayNum);

    }

    /** 交易总览： 转化率 */
    private Map<String, Object> conversionRate(List<OrderMain> orderMainList, List<Visitors> visitorsList) {

        Map<String, Object> map = new HashMap<>();

        // 访客数-下单数-支付数
        float visitorNums = Float.parseFloat(visitorsList.size() + "");
        float orderNums = Float.parseFloat(orderMainList.size() + "");
        float payNums = orderMainList.isEmpty()?0f: Float.parseFloat(orderMainList.stream().filter(orderMain -> orderMain.getPaidTime() != null).count()+"");

        // 下单转换率
        float orderVisitorRate = orderNums/visitorNums;
        // 下单支付转化率
        float payOrderRate = payNums/orderNums;
        // 支付转换率
        float payVisitorRate = payNums/visitorNums;
        DecimalFormat  fnum  =  new  DecimalFormat("##0.00");

        map.put("orderVisitorRate", fnum.format(orderVisitorRate));
        map.put("payOrderRate", fnum.format(payOrderRate));
        map.put("payVisitorRate", fnum.format(payVisitorRate));
        return map;
    }

    private Map<String, Object> getTransactionDate(String typeName, Float aheadDayNum, Float aheadDoubleDayNum) {

        HashMap<String, Object> map = new HashMap<>();

        // 数据增长类型：flat-不变 up-增了  down 降了
        float typeNum = aheadDayNum - aheadDoubleDayNum;
        String type;
        if (typeNum == 0){
            type="flat";
        } else if(typeNum > 0){
            type = "up";
        }else {
            type = "down";
        }

        // 环比增长计算： （本次数据－上次数据）÷上次数据
        float relativeUp = aheadDoubleDayNum == 0f? 0f: (aheadDayNum-aheadDoubleDayNum) /aheadDoubleDayNum;

        DecimalFormat  fnum  =  new  DecimalFormat("##0.00");
        map.put("type", type);
        map.put(typeName, aheadDayNum);
        map.put("rate", fnum.format(Math.abs(relativeUp)));
        return map;
    }

    // ==============================交易趋势===========================================

    /** 下单支付转化率趋势图 */
    private Map<String, Object> orderPayRateTrendChart(Map<LocalDateTime, List<OrderMain>> orderMainsGroupByDay) {
        Map<String, Object> orderPayRate = new HashMap<>();
        List<String> dayList = new ArrayList<>();
        List<Object> rateList = new ArrayList<>();

        // 计算每天的下单支付转化率
        for (LocalDateTime localDateTimeKey: orderMainsGroupByDay.keySet()) {
            // 获取每天的订单
            List<OrderMain> dayOrderMains = orderMainsGroupByDay.get(localDateTimeKey);

            float rate;
            if (!dayOrderMains.isEmpty()) {
                // 获取每天已支付的订单
                List<OrderMain> alreadyPayOrder = dayOrderMains.stream().filter(s -> s.getPaidTime() != null).collect(Collectors.toList());
                // 计算下单支付转化率， 并且保留两位小数
                rate= dayOrderMains.isEmpty() ? 0 : Float.parseFloat(alreadyPayOrder.size() == 0 ? "0" : alreadyPayOrder.size() + "") / Float.parseFloat(dayOrderMains.size() + "");
            }else {
                rate = 0;
            }

            // 格式化返回前端的 日期格式 和 转化率
            Map<String, String> map = this.trendChartDataFormat(localDateTimeKey, rate);
            dayList.add(map.get("day"));
            rateList.add(Float.parseFloat(map.get("rate")));
        }

        orderPayRate.put("dayList", dayList);
        orderPayRate.put("numberList", rateList);
        return orderPayRate;
    }

    /** 支付转化率趋势图 */
    private Map<String, Object> payVisitorsTrendChart(Map<LocalDateTime, List<OrderMain>> orderMainsGroupByDay, Map<LocalDateTime, List<Visitors>> listGroupVisitors) {

        Map<String, Object> orderPayRate = new HashMap<>();
        List<String> dayList = new ArrayList<>();
        List<Object> rateList = new ArrayList<>();
        
        for (LocalDateTime localDateTimeKey: orderMainsGroupByDay.keySet()) {
            // 获取每天的订单
            List<OrderMain> dayOrderMains = orderMainsGroupByDay.get(localDateTimeKey);
            // 获取该天订单的支付订单数
            float payNum = Float.parseFloat(dayOrderMains.stream().filter(orderMain -> orderMain.getPaidTime() != null).count() + "");
            // 获取当天的访客数
            float visitorsNum = Float.parseFloat(listGroupVisitors.get(localDateTimeKey).size() + "");
            // 计算支付转化率
            float rate = visitorsNum == 0? 0 : payNum/visitorsNum;
            // 格式化返回前端的 日期格式 和 转化率
            Map<String, String> map = this.trendChartDataFormat(localDateTimeKey, rate);
            dayList.add(map.get("day"));
            rateList.add(Float.parseFloat(map.get("rate")));
        }

        orderPayRate.put("dayList", dayList);
        orderPayRate.put("numberList", rateList);
        return orderPayRate;

    }

    /** 支付买家数趋势图 */
    private Map<String, Object> payBuyerTrendChart(Map<LocalDateTime, List<OrderMain>> orderMainsGroupByDay) {

        Map<String, Object> map = new HashMap<>();
        List<String> dayList = new ArrayList<>();
        List<Object> numberList = new ArrayList<>();

        orderMainsGroupByDay.forEach((localDateTimeKey, listOrderMainValue) -> {

            List<OrderMain> orderMains = orderMainsGroupByDay.get(localDateTimeKey);
            int payNumber;
            if (!orderMains.isEmpty()) {
                // 获取买家数
                List<Long> members = orderMains.stream().filter(s-> s.getPaidTime() != null).map(OrderMain::getMemberId).distinct().collect(Collectors.toList());
                payNumber = members.size();
            }else {
                payNumber = 0;
            }
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM-dd");
            String dayFormat = formatter.format(localDateTimeKey);
            dayList.add(dayFormat);
            numberList.add(payNumber);

        });

        map.put("dayList", dayList);
        map.put("numberList", numberList);
        return map;
    }

    /** 下单买家数趋势图 */
    private Map<String, Object> orderBuyerTrendChart(Map<LocalDateTime, List<OrderMain>> orderMainsGroupByDay) {

        Map<String, Object> map = new HashMap<>();
        List<String> dayList = new ArrayList<>();
        List<Object> numberList = new ArrayList<>();

        orderMainsGroupByDay.forEach((localDateTimeKey, listOrderMainValue) -> {

            List<OrderMain> orderMains = orderMainsGroupByDay.get(localDateTimeKey);
            // 获取买家数
            int buyerNumber;
            if (!orderMains.isEmpty()) {
                List<Long> members = orderMains.stream().map(OrderMain::getMemberId).distinct().collect(Collectors.toList());
                buyerNumber = members.size();
            }else {
                buyerNumber = 0;
            }

            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM-dd");
            String dayFormat = formatter.format(localDateTimeKey);
            dayList.add(dayFormat);
            numberList.add(buyerNumber);

        });

        map.put("dayList", dayList);
        map.put("numberList", numberList);
        return map;
    }

    /** 客单价趋势图 */
    private Map<String, Object> unitPriceTrendChart(Map<LocalDateTime, List<OrderMain>> orderMainsGroupByDay) {
        Map<String, Object> map = new HashMap<>();
        List<String> dayList = new ArrayList<>();
        List<Object> numberList = new ArrayList<>();

        orderMainsGroupByDay.forEach((localDateTimeKey, listOrderMainValue) -> {

            List<OrderMain> orderMains = orderMainsGroupByDay.get(localDateTimeKey);

            float priceUnite;

            if (!orderMains.isEmpty()) {
                // 订单数量
                float orderManisNum = Float.parseFloat(orderMains.size()+"");
                // 订单应付总金额
                float amountSum = orderMains.stream().map(OrderMain::getOrderAmount).reduce(BigDecimal.ZERO, BigDecimal::add).floatValue();
                // 计算客单价  订单应付总金额 / 订单数量
                 priceUnite = amountSum / orderManisNum;
            }else {
                priceUnite = 0;
            }
            DecimalFormat fnum = new DecimalFormat("##0.00");
            Float priceUniteFormat = Float.parseFloat(fnum.format(priceUnite));

            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM-dd");
            String dayFormat = formatter.format(localDateTimeKey);
            dayList.add(dayFormat);
            numberList.add(priceUniteFormat);

        });

        map.put("dayList", dayList);
        map.put("numberList", numberList);
        return map;
    }

    /** 获取某个时间段内的订单，并且按天进行分组 */
    private Map<LocalDateTime, List<OrderMain>> listGroupOrderMains(Integer aheadDays, Long storeId, LocalDateTime localDateTime) {

        // 计算时间区间
        Map<String, String> timeInterval = this.getTimeInterval(aheadDays, localDateTime);
        String aheadTimeStr = timeInterval.get("aheadTimeStr");
        String nowTimeStr = timeInterval.get("nowTimeStr");

        // 查询某个时间段内的所有主单
        List<OrderMain> orderMains = this.listOrderRemains(aheadTimeStr, nowTimeStr, storeId);

        Map<LocalDateTime, List<OrderMain>> map;
        if (!orderMains.isEmpty()) {
            // 有订单信息： 将创建时间的时分秒设置为0，目的: 将订单按天分组
            orderMains.stream().forEach(s -> {
                LocalDateTime dayTime = this.timeConversionDay(s.getCreatedTime());
                s.setCreatedTime(dayTime);
            });
            // 将订单按天分组
            map = orderMains.stream().collect(Collectors.groupingBy(OrderMain::getCreatedTime));

        }else {
            // 查询结果无订单信息
            map = new HashMap<>();
        }


        // timeList: 存放昨天一直到前 aheadDays 天的日期
        List<LocalDateTime> timeList = new ArrayList<>();
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime nowTime = LocalDateTime.parse(nowTimeStr, df);
        for (int i=1; i<= aheadDays; i++) {
            LocalDateTime aheadIDay = nowTime.minusDays(i);
            timeList.add(aheadIDay);
        }

        // 判断 昨天一直到前 aheadDays天是否都有订单，如果没有，将没有的日期作为key, 空的 List<OrderMain> 作为值存放到集合中
        List<OrderMain> emptyList = new ArrayList<>();
        timeList.forEach(s -> {
            if (!map.containsKey(s)) {
                map.put(s, emptyList);
            }
        });

        // 将Map集合按照LocalDateTime从小到大的顺序排序
        Map<LocalDateTime, List<OrderMain>> orderMainsGroupByDay = sortByKey(map, false);
        return orderMainsGroupByDay;
    }

    /** 获取某个时间段内的访客数，并且按天进行分组 */
    private Map<LocalDateTime, List<Visitors>> listGroupVisitors(Integer aheadDays, Long storeId, LocalDateTime localDateTime) {

        // 计算时间区间
        Map<String, String> timeInterval = this.getTimeInterval(aheadDays, localDateTime);
        String aheadTimeStr = timeInterval.get("aheadTimeStr");
        String nowTimeStr = timeInterval.get("nowTimeStr");

        // 查询 aheadTimeStr 至 nowTimeStr 的所有访客数
        List<Visitors> visitorsList = this.listVisitors(aheadTimeStr, nowTimeStr, storeId);

        Map<LocalDateTime, List<Visitors>> map;

        if (!visitorsList.isEmpty()) {
            // 有订单信息： 将创建时间的时分秒设置为0，目的: 将订单按天分组
            visitorsList.stream().forEach(s -> {
                LocalDateTime dayTime = this.timeConversionDay(s.getCreatedTime());
                s.setCreatedTime(dayTime);
            });
            // 将订单按天分组
            map = visitorsList.stream().collect(Collectors.groupingBy(Visitors::getCreatedTime));

        }else {
            // 查询结果无订单信息
            map = new HashMap<>();
        }

        // timeList: 存放昨天一直到前 aheadDays 天的日期
        List<LocalDateTime> timeList = new ArrayList<>();
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime nowTime = LocalDateTime.parse(nowTimeStr, df);
        for (int i=1; i<= aheadDays; i++) {
            LocalDateTime aheadIDay = nowTime.minusDays(i);
            timeList.add(aheadIDay);
        }

        // 判断 昨天一直到前 aheadDays天是否都有订单，如果没有，将没有的日期作为key, 空的 List<OrderMain> 作为值存放到集合中
        List<Visitors> emptyList = new ArrayList<>();
        timeList.forEach(s -> {
            if (!map.containsKey(s)) {
                map.put(s, emptyList);
            }
        });

        // 将Map集合按照LocalDateTime从小到大的顺序排序
        Map<LocalDateTime, List<Visitors>> orderMainsGroupByDay = sortByKey(map, false);

        return orderMainsGroupByDay;
    }

    /** 趋势图:格式化返回前端的日期 以及 比率 */
    private Map<String, String> trendChartDataFormat(LocalDateTime localDateTime, float rate) {

        Map<String, String> map = new HashMap<>();
        DecimalFormat fnum = new DecimalFormat("##0.00");
        String rateStr = fnum.format(rate);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM-dd");
        String dayFormat = formatter.format(localDateTime);
        map.put("rate", rateStr );
        map.put("day", dayFormat);
        return map;

    }

    // ============================== 共有方法 ===========================================

    /**
     *  获取 nowTime 前 aheadDays 的时间日期。 返回的是 时间格式的字符串。同时会返回 nowTime 的字符串
     */
    private Map<String, String> getTimeInterval(Integer aheadDays, LocalDateTime nowTime) {

        HashMap<String, String> timeInterval = new HashMap<>();
        // 获取订单的查询区间
        LocalDateTime aheadTime = nowTime.minus(aheadDays, ChronoUnit.DAYS);
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd 00:00:00");

        String nowTimeStr = dateTimeFormatter.format(nowTime);
        String aheadTimeStr = dateTimeFormatter.format(aheadTime);

        timeInterval.put("aheadTimeStr", aheadTimeStr);
        timeInterval.put("nowTimeStr", nowTimeStr);

        return timeInterval;
    }

    /**
     * 对map集合按照key进行排序
     */
    private static <K extends Comparable<? super K>, V> Map<K, V> sortByKey(Map<K, V> map, boolean isDesc) {
        Map<K, V> result = Maps.newLinkedHashMap();
        if (isDesc) {
            map.entrySet().stream().sorted(Map.Entry.<K, V>comparingByKey().reversed())
                    .forEachOrdered(e -> result.put(e.getKey(), e.getValue()));
        } else {
            map.entrySet().stream().sorted(Map.Entry.<K, V>comparingByKey())
                    .forEachOrdered(e -> result.put(e.getKey(), e.getValue()));
        }
        return result;
    }

    /**
     * 将日期中的时分秒变为 00:00:00
     */
    private LocalDateTime timeConversionDay(LocalDateTime time) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd 00:00:00");
        String newCreatedTime = dateTimeFormatter.format(time);
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime dateTime = LocalDateTime.parse(newCreatedTime, df);
        return dateTime;
    }

    /**
     * 获取相对日期的主订单： 例如：如果aheadDays=1 就获取昨天和前天的主订单信息
     */
    private Map<String, List<OrderMain>> listRelativeOrderMains(Integer aheadDays, Long storeId) {

        Map<String, List<OrderMain>> map = new HashMap<>();

        // 获取aheadDays 天前的日期
        Map<String, String> timeInterval = this.getTimeInterval(aheadDays, LocalDateTime.now());
        String aheadTimeStr = timeInterval.get("aheadTimeStr");
        String nowTimeStr = timeInterval.get("nowTimeStr");

        // 获取 aheadDays x 2天 前的日期
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime aheadTime = LocalDateTime.parse(aheadTimeStr, df);
        Map<String, String> moreBeforeTimes = this.getTimeInterval(aheadDays, aheadTime);
        String aheadTimeDoubleStr = moreBeforeTimes.get("aheadTimeStr");


        // 查询 aheadTimeStr 到 昨天的订单
        List<OrderMain> aheadDayOrderMains = this.listOrderRemains(aheadTimeStr, nowTimeStr, storeId);
        // 查询 aheadTimeDoubleStr 到 aheadTimeStr 的订单
        List<OrderMain> aheadDoubleDayOrderMains = this.listOrderRemains(aheadTimeDoubleStr, aheadTimeStr, storeId);

        map.put("aheadDayOrderMains", aheadDayOrderMains);
        map.put("aheadDoubleDayOrderMains", aheadDoubleDayOrderMains);
        return map;
    }

    /**
     * 获得性对日期的访客数
     */
    private Map<String, List<Visitors>> listRelativeVisitors(Integer aheadDays, Long storeId) {

        Map<String, List<Visitors>> map = new HashMap<>();

        // 获取aheadDays 天前的日期
        Map<String, String> timeInterval = this.getTimeInterval(aheadDays, LocalDateTime.now());
        String aheadTimeStr = timeInterval.get("aheadTimeStr");
        String nowTimeStr = timeInterval.get("nowTimeStr");

        // 获取 aheadDays x 2天 前的日期
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime aheadTime = LocalDateTime.parse(aheadTimeStr, df);
        Map<String, String> moreBeforeTimes = this.getTimeInterval(aheadDays, aheadTime);
        String aheadTimeDoubleStr = moreBeforeTimes.get("aheadTimeStr");

        // 获取aheadDays 至 昨天的访客数
        List<Visitors> numDaysAgoVisitors = this.listVisitors(aheadTimeStr, nowTimeStr, storeId);

        // 获取 aheadTimeDoubleStr 至 aheadTimeStr 的访客数
        List<Visitors> doubleNumDaysAgoVisitors = this.listVisitors(aheadTimeDoubleStr, aheadTimeStr, storeId);

        map.put("numDaysAgoVisitors", numDaysAgoVisitors);
        map.put("doubleNumDaysAgoVisitors", doubleNumDaysAgoVisitors);

        return map;
    }

    /**
     * 获取指点时间区间内的订单
     */
    private List<OrderMain> listOrderRemains(String beginTime, String endTime, Long storeId) {
        List<OmnipotentWrapper> setCondition = new ArrayList<>();
        // ge: >=  lt: <
        setCondition.add(OmnipotentWrapper.setWrapper("ge", "created_time", beginTime));
        setCondition.add(OmnipotentWrapper.setWrapper("lt", "created_time", endTime));
        setCondition.add(OmnipotentWrapper.setWrapper("eq", "store_id", storeId));
        setCondition.add(OmnipotentWrapper.setWrapper("eq", "deleted", 0));
        List<OrderMain> orderMains = shopSaleOrderFeignService.omniQueryOrderMain(setCondition).getData();
        return orderMains;
    }

    /**
     * 获取指定时间区间内访客数信息
     */
    private List<Visitors> listVisitors(String beginTime, String endTime, Long storeId) {
        ArrayList<OmnipotentWrapper> wrapperList = new ArrayList<>();
        wrapperList.add(OmnipotentWrapper.setWrapper("ge", "created_time", beginTime));
        wrapperList.add(OmnipotentWrapper.setWrapper("lt", "created_time", endTime));
        wrapperList.add(OmnipotentWrapper.setWrapper("eq", "store_id", storeId));
        List<Visitors> numDaysAgoisitors = userFeignService.queryVisitorsBatch(wrapperList).getData();
        return numDaysAgoisitors;
    }

}
